package com.chenfan.magic.base;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.chenfan.ccp.common.result.IResultCode;
import com.chenfan.ccp.common.result.ResultCode;
import com.chenfan.magic.constant.BladeConstant;
import com.chenfan.magic.utils.AES;
import com.chenfan.magic.utils.FastJsonKit;
import com.chenfan.magic.utils.MapKit;
import com.chenfan.magic.utils.ObjectUtil;
import com.google.common.collect.Maps;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;

import java.io.Serializable;
import java.util.Map;
import java.util.Optional;

/**
 * 统一API响应结果封装
 *
 * @author troy
 */
@Data
@ToString
@ApiModel(description = "返回信息")
@NoArgsConstructor
@Slf4j
public class R implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "状态码", required = true)
    private int code;
    @ApiModelProperty(value = "承载数据: Map 容器类型")
    private Map<String, Object> data = Maps.newHashMap();
    @ApiModelProperty(value = "承载数据: 加密")
    private String encryptData;
    @ApiModelProperty(value = "返回消息", required = true)
    private String msg;
    @ApiModelProperty(value = "通信时间戳", required = true)
    private Long timestamp = System.currentTimeMillis();

    private R(IResultCode resultCode) {
        this(resultCode.getCode(), resultCode.getMessage());
    }

    private R(IResultCode resultCode, String msg) {
        this(resultCode.getCode(), msg);
    }

    private R(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    /**
     * 判断返回是否为成功
     *
     * @param result Result
     * @return 是否成功
     */
    public static boolean isSuccess(@Nullable R result) {
        return Optional.ofNullable(result)
                .map(x -> ObjectUtil.nullSafeEquals(ResultCode.SUCCESS.getCode(), x.code))
                .orElse(Boolean.FALSE);
    }

    /**
     * 判断返回是否为成功
     *
     * @param result Result
     * @return 是否成功
     */
    public static boolean isNotSuccess(@Nullable R result) {
        return !R.isSuccess(result);
    }

    public static R success() {
        return new R(ResultCode.SUCCESS, BladeConstant.DEFAULT_SUCCESS_MESSAGE);
    }

    public static R data(Object object) {
        return new R(ResultCode.SUCCESS).put(object);
    }

    /**
     * 返回R
     *
     * @param msg 消息
     * @return R
     */
    public static R success(String msg) {
        return new R(ResultCode.SUCCESS, msg);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @return R
     */
    public static R success(IResultCode resultCode) {
        return new R(resultCode);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param msg        消息
     * @return R
     */
    public static R success(IResultCode resultCode, String msg) {
        return new R(resultCode, msg);
    }

    public static R fail() {
        return new R(ResultCode.FAIL, BladeConstant.DEFAULT_FAILURE_MESSAGE);
    }

    /**
     * 返回R
     *
     * @param msg 消息
     * @return R
     */
    public static R fail(String msg) {
        return new R(ResultCode.FAIL, msg);
    }


    /**
     * 返回R
     *
     * @param code 状态码
     * @param msg  消息
     * @return R
     */
    public static R fail(int code, String msg) {
        return new R(code, msg);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @return R
     */
    public static R fail(IResultCode resultCode) {
        return new R(resultCode);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param msg        消息
     * @return R
     */
    public static R fail(IResultCode resultCode, String msg) {
        return new R(resultCode, msg);
    }

    /**
     * 返回R
     *
     * @param flag 成功状态
     * @return R
     */
    public static R status(boolean flag) {
        return flag ? success(BladeConstant.DEFAULT_SUCCESS_MESSAGE) : fail(BladeConstant.DEFAULT_FAILURE_MESSAGE);
    }


    /**
     * put 语法实现
     * 默认的数据键
     */
    public static final String DATA_KEY = "result";

    public R put(String key, Object value) {
        if (StringUtils.isBlank(key)) {
            key = DATA_KEY;
        }
        //注意: 重复键将会被覆盖
        this.data.put(key, value);
        return this;
    }

    public R put(Object value) {
        //注意: 重复键将会被覆盖
        this.data.put(DATA_KEY, value);
        return this;
    }

    public R putAll(Map<String, Object> data) {
        //注意: 重复键将会被覆盖
        this.data.putAll(data);
        return this;
    }

    public R putAll(R r) {
        //注意: 重复键将会被覆盖
        this.data.putAll(r.getData());
        return this;
    }

    public Object get() {
        return this.data.get(DATA_KEY);
    }

    public R remove(String key) {
        this.data.remove(key);
        return this;
    }

    public R remove() {
        this.data.remove(DATA_KEY);
        return this;
    }

    public R clear() {
        this.data.clear();
        return this;
    }

    public R encrypt(String appSecret) {
        return encrypt(appSecret, true, false);
    }

    /**
     * 0-加密, 1-不加密
     * @param appSecret
     * @param encryptCode
     * @return
     */
    public R encrypt(String appSecret, int encryptCode) {
        return encrypt(appSecret, (encryptCode == 0), false);
    }

    public R encrypt(String appSecret, boolean encrypt) {
        return encrypt(appSecret, encrypt, false);
    }

    public R encrypt(String appSecret, boolean encrypt, boolean stay) {
        if (encrypt && MapKit.isNotEmpty(this.data)) {
            try {
                JSONObject jsonObject = new JSONObject(this.data);
                this.encryptData = jsonObject.toString(SerializerFeature.WriteDateUseDateFormat);
                log.info(this.encryptData);
                this.encryptData = AES.encrypt(this.encryptData, appSecret);
            } catch (Exception e) {
                this.code = 500;
                this.msg = "协议数据加密异常";
            }
            if (!stay) {
                this.data = Maps.newHashMap();
            }
        }
        return this;
    }

    public R decrypt(String appSecret) {
        return decrypt(appSecret, false);
    }

    public R decrypt(String appSecret, boolean stay) {
        try {
            this.encryptData = AES.decrypt(this.encryptData, appSecret);
            this.data = FastJsonKit.jsonstring2Map(this.encryptData);
        } catch (Exception e) {
            this.code = 500;
            this.msg = "协议数据解密异常";
        }
        if (!stay) {
            this.encryptData = "";
        }
        return this;
    }

    public boolean takeStatus() {
        return this.code == ResultCode.SUCCESS.getCode();
    }
}


